package com.example.demo.Recursion;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 使用尾递归的类,目的是对外统一方法
 *
 * @date： 2021/7/27
 * @author: wbx
 */
public class TailInvoke {
    /**
     * 统一结构的方法,获得当前递归的下一个递归
     *
     * @param nextFrame 下一个递归
     * @param <T>       T
     * @return 下一个递归
     */
    public static <T> TailRecursion<T> call(final TailRecursion<T> nextFrame) {
        return nextFrame;
    }

    /**
     * 结束当前递归，重写对应的默认方法的值,完成状态改为true,设置最终返回结果,设置非法递归调用
     *
     * @param value 最终递归值
     * @param <T>   T
     * @return 一个isFinished状态true的尾递归, 外部通过调用接口的invoke方法及早求值, 启动递归求值。
     */
    public static <T> TailRecursion<T> done(T value) {
        return new TailRecursion<T>() {
            @Override
            public TailRecursion<T> apply() {
                throw new Error("递归已经结束,非法调用apply方法");
            }

            @Override
            public boolean isFinished() {
                return true;
            }

            @Override
            public T getResult() {
                return value;
            }
        };
    }

    public static void main(String[] args) {
        NoOOMcount(10,20);
    }

    public static void count(int number) {
        if(number == 100000000) {
            System.out.println("number==> " + number);
            return;
        }
        number++;
        System.out.println("number==> " + number);
        count(number);
    }

    public static TailRecursion<Integer> NoOOMcount(int result,int number) {
        AtomicInteger integer = new AtomicInteger(number);
        AtomicInteger reultInteger = new AtomicInteger(result);
        if(reultInteger.get() == 100000000) {
            System.out.println("number==> " + number);
            return TailInvoke.done(number);
        } else {
            System.out.println("number==> " + integer.get());
            return TailInvoke.call(() -> NoOOMcount(reultInteger.incrementAndGet(), integer.incrementAndGet()));
        }
    }

    /**
     * 阶乘计算 -- 使用尾递归接口完成
     * @param factorial 当前递归栈的结果值
     * @param number 下一个递归需要计算的值
     * @return 尾递归接口,调用invoke启动及早求值获得结果
     */
    public static TailRecursion<Integer> factorialTailRecursion(final int factorial, final int number) {
        if (number == 1)
            return TailInvoke.done(factorial);
        else
            return TailInvoke.call(() -> factorialTailRecursion(factorial + number, number - 1));
    }
}
